﻿namespace WebServiceExtensions.CallCounterExtension
{
	#region Namespaces

	using System;
    using System.Linq;
	using System.Web.Services.Protocols;

	using WebServiceExtensions.Configurations.CallCounter;
	using WebServiceExtensions.Configurations.Common;

    #endregion

	/// <summary>
	///   Extension for call counting
	/// </summary>
	public class CallCounterExtension : SoapExtension
	{
		#region Fields (2) 

	    /// <summary>
	    /// Gets the call counter manager.
	    /// </summary>
	    private static CallCounter callCounter;
        /// <summary>
        /// Represents config view
        /// </summary>
        private WebServiceExtensionConfigurationView configView = new WebServiceExtensionConfigurationView();

		#endregion Fields 

		#region Properties (2) 

        /// <summary>
        /// Gets the call counter manager.
        /// </summary>
        /// <value>The call counter manager.</value>
        public static CallCounter CallCounters
        {
            get
            {
                if (callCounter == null)
                {
                    callCounter = new CallCounter();
                    callCounter.InitializeCounters();
                }

                return callCounter;
            }

            private set
            {
                callCounter = value;
            }
        }

        /// <summary>
        /// Gets or sets the config view.
        /// </summary>
        /// <value>The config view.</value>
        internal WebServiceExtensionConfigurationView ConfigView
        {
            get
            {
                return this.configView;
            }

            set
            {
                this.configView = value;
            }
        }

		#endregion Properties 

		#region Methods (4) 

		// Public Methods (4) 

		// Public Methods (4) 
		/// <summary>
		///   When overridden in a derived class, allows a SOAP extension to initialize data specific to a class implementing an XML Web service at a one time performance cost.
		/// </summary>
		/// <param name = "serviceType">The type of the class implementing the XML Web service to which the SOAP extension is applied.</param>
		/// <returns>
		///   The <see cref = "T:System.Object" /> that the SOAP extension initializes for caching.
		/// </returns>
		public override object GetInitializer(Type serviceType)
		{
		   return null;
		}

		/// <summary>
		///   When overridden in a derived class, allows a SOAP extension to initialize data specific to an XML Web service method using an attribute applied to the XML Web service method at a one time performance cost.
		/// </summary>
		/// <param name = "methodInfo">A <see cref = "T:System.Web.Services.Protocols.LogicalMethodInfo" /> representing the specific function prototype for the XML Web service method to which the SOAP extension is applied.</param>
		/// <param name = "attribute">The <see cref = "T:System.Web.Services.Protocols.SoapExtensionAttribute" /> applied to the XML Web service method.</param>
		/// <returns>
		///   The <see cref = "T:System.Object" /> that the SOAP extension initializes for caching.
		/// </returns>
		public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
		{
            return null;
		}

		/// <summary>
		///   When overridden in a derived class, allows a SOAP extension to initialize itself using the data cached in the <see
		///    cref = "M:System.Web.Services.Protocols.SoapExtension.GetInitializer(System.Web.Services.Protocols.LogicalMethodInfo,System.Web.Services.Protocols.SoapExtensionAttribute)" /> method.
		/// </summary>
		/// <param name = "initializer">The <see cref = "T:System.Object" /> returned from <see cref = "M:System.Web.Services.Protocols.SoapExtension.GetInitializer(System.Web.Services.Protocols.LogicalMethodInfo,System.Web.Services.Protocols.SoapExtensionAttribute)" /> cached by ASP.NET.</param>
		public override void Initialize(object initializer)
		{
		    return;
		}

		/// <summary>
		///   When overridden in a derived class, allows a SOAP extension to receive a <see
		///    cref = "T:System.Web.Services.Protocols.SoapMessage" /> to process at each <see
		///    cref = "T:System.Web.Services.Protocols.SoapMessageStage" />.
		/// </summary>
		/// <param name = "message">The <see cref = "T:System.Web.Services.Protocols.SoapMessage" /> to process.</param>
		public override void ProcessMessage(SoapMessage message)
		{
            if (message.Stage == SoapMessageStage.AfterSerialize)
            {
                string typeName = message.MethodInfo.DeclaringType.FullName;
                string methodName = message.MethodInfo.Name;

                bool enableCounting = true;

                if (this.configView.CallCounterSettings != null && this.configView.CallCounterSettings.EnableCallCounting)
                {
                    if (this.configView.CallCounterSettings.Types != null)
                    {

                        TypeData t = this.configView.CallCounterSettings.Types.First(
                        s => string.Compare(s.Name, typeName, StringComparison.OrdinalIgnoreCase) == 0);

                        if (t != null && t.EnableCallCounting)
                        {
                            if (t.Methods != null)
                            {
                                Method m =
                                    t.Methods.First(
                                        s => string.Compare(s.Name, methodName, StringComparison.OrdinalIgnoreCase) == 0);

                                if (m != null && !m.EnableCallCounting)
                                {
                                    enableCounting = false;
                                }
                            }
                        }
                        else
                        {
                            enableCounting = false;
                        }
                    }
                }
                else
                {
                    enableCounting = false;
                }

                if (enableCounting)
                {
                    if (callCounter == null)
                    {
                        CallCounters = new CallCounter();
                        CallCounters.InitializeCounters();
                    }

                    callCounter.UpdateCount(typeName, methodName);
                }
            }
		}

		#endregion Methods 
	}
}